/**
 * Copyright (c) 2007-2008 Nearchos Paspallis
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * AspectSense
 *
 * Middleware for annotation-based, context-aware and adaptive services for
 * mobile and ubiquitous computing
 *
 * This project is an open-source effort, initiated by Nearchos Paspallis as
 * part of his PhD work at the University of Cyprus (http://www.ucy.ac.cy).
 *
 * More information about the project is available at "http://aspectsense.org".
 */

package org.aspectsense.framework;

import org.aspectsense.framework.PackageManager;
import org.aspectsense.gui.util.*;
import org.aspectsense.gui.desktop.UserPreferencesFrame;
import org.aspectsense.gui.client.ManagementConsole;

import javax.swing.*;
import java.util.logging.Logger;
import java.util.LinkedList;
import java.io.File;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

/**
 * @author Nearchos Paspallis [nearchos@cs.ucy.ac.cy]
 *         Date: Jan 7, 2008
 *         Time: 11:58:30 AM
 */
public class Controller
{
    public static final Color LIGHT_BLUE = new Color(239, 239, 255);

    public static final String ASPECT_SENSE_HELP_URL = "http://aspectsense.org";

    private static final Logger logger = Logger.getLogger(Controller.class.getCanonicalName());

    private static final PackageManager packageManager = PackageManager.getInstance();

    // ----------------- Singleton pattern implementation ------------------- //

    private static Controller instance = null;

    /**
     * Provides access to the lazy-loaded singleton instance of the
     * {@link Controller}.
     *
     * @return an instance of {@link Controller}
     */
    public static Controller getInstance()
    {
        synchronized(Controller.class)
        {
            if(instance == null) instance = new Controller();

            return instance;
        }
    }

    private Controller()
    {
        logger.fine("Starting instance of " + Controller .class.getCanonicalName());
    }

    // --------------- End of singleton pattern implementation -------------- //

    // ---------------------- System Tray Commands -------------------------- //

    public void installComponent()
    {
        final JFileChooser fileChooser = new JFileChooser(".");
        fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        fileChooser.setFileFilter(new JarFileFilter());
        if(fileChooser.showDialog(JOptionPane.getRootFrame(), "Select") == JFileChooser.APPROVE_OPTION)
        {
            File selectedFile = fileChooser.getSelectedFile();

            if(selectedFile.isDirectory())
            {
                LinkedList<File> jarFiles = new LinkedList<File>();

                File [] allFiles = selectedFile.listFiles();
                for(File file : allFiles)
                {
                    if(file.isFile() && file.getName().toLowerCase().endsWith(".jar"))
                    {
                        jarFiles.add(file);
                    }
                }

                final JarFilesGrid jarFilesGrid = new JarFilesGrid(jarFiles);

                Object [] messages = new Object [] {
                        "Select JAR files to be loaded:",
                        jarFilesGrid
                };

                JOptionPane.showMessageDialog(JOptionPane.getRootFrame(),
                        messages,
                        "JAR loading results",
                        JOptionPane.INFORMATION_MESSAGE);

                final LinkedList<File> selectedJarFiles = new LinkedList<File>();

                int count = 0;
                for(File jarFile : jarFiles)
                {
                    if(jarFilesGrid.checkBoxes[count].isSelected())
                    {
                        selectedJarFiles.add(jarFile);
                    }

                    count++;
                }

                for(final File selectedJarFile : selectedJarFiles)
                {
                    logger.info("Installing package: " + selectedJarFile + " ...");

                    packageManager.installPackage(selectedJarFile);
                }
            }
            else if(selectedFile.getName().toLowerCase().endsWith(".jar"))
            {
                logger.info("Installing package: " + selectedFile + " ...");

                packageManager.installPackage(selectedFile);
            }
        }
    }

    public void uninstallComponent()
    {
        //todo
    }

    public void userPreferences()
    {
        UserPreferencesFrame.show();
    }

    /**
     * Launches the management console
     */
    public void managementConsole()
    {
        new ManagementConsole();
    }

    public void help()
    {
        WebBrowserLaunch.openURL(ASPECT_SENSE_HELP_URL);
    }

    public void about()
    {
        AboutFrame.show();
    }

    // todo reconsider public scope of method for security reasons
    public void exit(final TrayIcon trayIcon)
    {
        final Object message = "Are you sure you want to exit?";
        int answer = JOptionPane.showConfirmDialog(
                JOptionPane.getRootFrame(),
                message,
                "Exit confirmation",
                JOptionPane.YES_NO_OPTION,
                JOptionPane.QUESTION_MESSAGE);

        if(answer == JOptionPane.YES_OPTION)
        {
            //todo terminate components/applications

            final SystemTray systemTray = SystemTray.getSystemTray();
            systemTray.remove(trayIcon);

            System.exit(0);
        }
    }

    // ------------------- End of System Tray Commands ---------------------- //

    private static class JarFilesGrid extends JPanel
    {
        private final JCheckBox [] checkBoxes;

        JarFilesGrid(final LinkedList<File> jarFiles)
        {
            super(new BorderLayout());


            JPanel checkBoxesPanel = new JPanel();
            checkBoxesPanel.setLayout(new BoxLayout(checkBoxesPanel, BoxLayout.Y_AXIS));
            checkBoxesPanel.setBorder(BorderFactory.createEtchedBorder());

            checkBoxes = new JCheckBox[jarFiles.size()];

            int count = 0;
            for(File file : jarFiles)
            {
                checkBoxes[count] = new JCheckBox();
                checkBoxes[count].setOpaque(false);
                checkBoxes[count].setSelected(true);
                JPanel panel = new JPanel(new BorderLayout());
                panel.setBackground(count % 2 == 0 ? LIGHT_BLUE : Color.WHITE);
                panel.add(checkBoxes[count], BorderLayout.WEST);
                panel.add(new JLabel(file.getName()), BorderLayout.CENTER);

                checkBoxesPanel.add(panel);

                count++;
            }

            JPanel buttonsPanel = new JPanel();

            JButton selectAllButton = new JButton("Select All");
            selectAllButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    for(JCheckBox checkBox : checkBoxes)
                    {
                        checkBox.setSelected(true);
                    }
                }
            });

            JButton unselectAllButton = new JButton("Unselect All");
            unselectAllButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    for(JCheckBox checkBox : checkBoxes)
                    {
                        checkBox.setSelected(false);
                    }
                }
            });

            buttonsPanel.add(selectAllButton);
            buttonsPanel.add(unselectAllButton);

            add(checkBoxesPanel, BorderLayout.CENTER);
            add(buttonsPanel, BorderLayout.SOUTH);
        }
    }

    /**
     *
     */
    private static class ComponentsGrid extends JPanel
    {
        private final JCheckBox [] checkBoxes;

        ComponentsGrid(final LinkedList<Class> components)
        {
            super(new BorderLayout());

            JPanel checkBoxesPanel = new JPanel();
            checkBoxesPanel.setLayout(new BoxLayout(checkBoxesPanel, BoxLayout.Y_AXIS));
            checkBoxesPanel.setBorder(BorderFactory.createEtchedBorder());

            checkBoxes = new JCheckBox[components.size()];

            int count = 0;
            for(Class clazz : components)
            {
                checkBoxes[count] = new JCheckBox();
                checkBoxes[count].setOpaque(false);
                checkBoxes[count].setSelected(true);
                JPanel panel = new JPanel(new BorderLayout());
                panel.setBackground(count % 2 == 0 ? LIGHT_BLUE : Color.WHITE);
                panel.add(checkBoxes[count], BorderLayout.WEST);
                panel.add(new JLabel(clazz.getCanonicalName()), BorderLayout.CENTER);

                checkBoxesPanel.add(panel);

                count++;
            }

            JPanel buttonsPanel = new JPanel();

            JButton selectAllButton = new JButton("Select All");
            selectAllButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    for(JCheckBox checkBox : checkBoxes)
                    {
                        checkBox.setSelected(true);
                    }
                }
            });

            JButton unselectAllButton = new JButton("Unselect All");
            unselectAllButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    for(JCheckBox checkBox : checkBoxes)
                    {
                        checkBox.setSelected(false);
                    }
                }
            });

            buttonsPanel.add(selectAllButton);
            buttonsPanel.add(unselectAllButton);

            add(checkBoxesPanel, BorderLayout.CENTER);
            add(buttonsPanel, BorderLayout.SOUTH);
        }
    }
}